package cc.rengu.igas.channel.wechat.core.service.trans;

import cc.rengu.igas.channel.wechat.common.constant.*;
import cc.rengu.igas.channel.wechat.common.enums.RespCodeEnum;
import cc.rengu.igas.channel.wechat.core.model.ChnlBizResponse;
import cc.rengu.igas.channel.wechat.core.service.base.AuthService;
import cc.rengu.igas.channel.wechat.facade.request.WechatGetOpenIdRequest;
import cc.rengu.igas.channel.wechat.facade.response.WechatGetOpenIdResponse;
import cc.rengu.jradp.schedule.Schedule;
import cc.rengu.oltp.service.common.constant.AppParamConstant;
import cc.rengu.oltp.service.common.constant.TreeNodeConstant;
import cc.rengu.oltp.service.common.dao.KeyInfoMapper;
import cc.rengu.oltp.service.common.dao.SecPlanInfoMapper;
import cc.rengu.oltp.service.common.dao.impl.KeyInfoMapperImpl;
import cc.rengu.oltp.service.common.dao.impl.SecPlanInfoMapperImpl;
import cc.rengu.oltp.service.common.entity.DstChannelCfg;
import cc.rengu.oltp.service.common.entity.KeyInfo;
import cc.rengu.oltp.service.common.entity.SecPlanInfo;
import cc.rengu.oltp.service.common.entity.SysParam;
import cc.rengu.oltp.service.model.BizException;
import cc.rengu.oltp.service.realize.SysParamService;
import cc.rengu.oltp.service.realize.impl.SysParamServiceImpl;
import cc.rengu.oltp.utility.util.ConvertUtil;
import cc.rengu.oltp.utility.util.RedisUtil;
import cc.rengu.oltp.utility.util.XmlTreeUtil;
import cc.rengu.utility.communication.HttpMethod;

import java.util.*;

/**
 * 获取用户OpenId
 * getOpenId  -- 获取openId时会同时获取用户信息
 * getPayOpenId  -- 只获取openId
 */
public class WechatGetOpenIdService extends AuthService {
    @Override
    protected Object beforeBizProcess() throws Exception {
        WechatGetOpenIdRequest getOpenIdRequest = new WechatGetOpenIdRequest();
        ConvertUtil.convertOutput(getOpenIdRequest);
        return getOpenIdRequest;
    }

    @Override
    protected ChnlBizResponse callBizService(Object request) throws Exception {
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        int iReturnCode = 0;
        String secret = null;
        WechatGetOpenIdResponse getOpenIdResponse = new WechatGetOpenIdResponse();
        WechatGetOpenIdRequest getOpenIdRequest = (WechatGetOpenIdRequest) request;
        String instId = getOpenIdRequest.getHeader().getInstId();
        DstChannelCfg dstChannelCfg = (DstChannelCfg) xmlTreeUtil.getXmlTreeObjectValue(WechatTreeNodeConstant.DST_CHANNEL_CFG, DstChannelCfg.class);
        /* 根据通道安全计划获取安全计划 */
        SecPlanInfoMapper secPlanInfoMapper = new SecPlanInfoMapperImpl();
        List<SecPlanInfo> secPlanInfoList = secPlanInfoMapper.selectSecPlanInfoBySecPlanId(instId, dstChannelCfg.getSecPlanId());
        rglog.debug("secPlanInfo-key = <{}>", instId + dstChannelCfg.getSecPlanId());
        if (null != secPlanInfoList && !secPlanInfoList.isEmpty()) {
            Optional<SecPlanInfo> secPlanInfoOpt = secPlanInfoList.stream().filter(item -> item.getSecPlanType().equals(WechatParamConstant.SECRET_KEY_TYPE)).findFirst();
            if (secPlanInfoOpt.isPresent()) {
                KeyInfoMapper keyInfoMapper = new KeyInfoMapperImpl();
                KeyInfo keyInfo = keyInfoMapper.selectKeyInfoByPrimaryKey(instId + secPlanInfoOpt.get().getSecPlanId() + secPlanInfoOpt.get().getSecPlanType());
                rglog.debug("keyInfo.key = <{}>", instId + secPlanInfoOpt.get().getSecPlanId() + secPlanInfoOpt.get().getSecPlanType());
                if (keyInfo != null) {
                    secret = keyInfo.getKeyValue();
                }
            }
        }
        if (secret == null) {
            rglog.error("获取服务商secret失败");
            throw new BizException(RespCodeEnum.GET_THIRD_MCHNT_KEY_ERROR.getRespCode(), RespCodeEnum.GET_THIRD_MCHNT_KEY_ERROR.getRespDesc());
        }
        xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.TXN_NUM, getOpenIdRequest.getHeader().getTxnNum());
        Map<String, String> paramMap = new HashMap<>();
        if ("APP".equals(getOpenIdRequest.getPayType())) {
            paramMap.put("appid", getOpenIdRequest.getAppid());
            paramMap.put("secret", getOpenIdRequest.getSecret());
            paramMap.put("code", getOpenIdRequest.getAuthCode());
        } else if ("MINI".equals(getOpenIdRequest.getPayType())) {
            paramMap.put("appid", getOpenIdRequest.getAppid());
            paramMap.put("secret", getOpenIdRequest.getSecret());
            paramMap.put("js_code", getOpenIdRequest.getAuthCode());
        } else {
            paramMap.put("appid", dstChannelCfg.getSubAppId());
            paramMap.put("secret", secret);
            paramMap.put("code", getOpenIdRequest.getAuthCode());
        }
        paramMap.put("grant_type", "authorization_code");
        SysParamService sysParamService = new SysParamServiceImpl();
        SysParam sysParam = null;
        String requestUrl = "";
        if ("getPayOpenId".equals(getOpenIdRequest.getHeader().getTxnNum())) {
            sysParam = sysParamService.getSysParamInfo(AppParamConstant.DEFAULT_INSTID, WechatConfigConstant.WECHAT_CONF_NODE, WechatConfigConstant.WECHAT_DIRECT_LINE_OPEN_ID_URL);
            if (sysParam == null) {
                throw new BizException(RespCodeEnum.CONFIG_PARAM_NOT_EXIST.getRespCode(), RespCodeEnum.CONFIG_PARAM_NOT_EXIST.getRespDesc());
            }
            requestUrl = generateHttpUrl(sysParam.getParamValue(), paramMap);
        } else {
            if ("MINI".equals(getOpenIdRequest.getPayType())) {
                sysParam = sysParamService.getSysParamInfo(AppParamConstant.DEFAULT_INSTID,
                        WechatConfigConstant.WECHAT_CONF_NODE, WechatConfigConstant.WECHAT_JSCODE_SESSION_URL);
            } else {
                sysParam = sysParamService.getSysParamInfo(AppParamConstant.DEFAULT_INSTID,
                        WechatConfigConstant.WECHAT_CONF_NODE, WechatConfigConstant.WECHAT_OPEN_ID_URL);
            }
            if (sysParam == null) {
                throw new BizException(RespCodeEnum.CONFIG_PARAM_NOT_EXIST.getRespCode(), RespCodeEnum.CONFIG_PARAM_NOT_EXIST.getRespDesc());
            }
            requestUrl = generateHttpUrl(sysParam.getParamValue(), paramMap);
        }
        xmlTreeUtil.setXmlTreeStringValue(WechatTreeNodeConstant.DEFINE_HTTP_URL_NODE, requestUrl);
        Schedule schedule = new Schedule();
        if ("getPayOpenId".equals(getOpenIdRequest.getHeader().getTxnNum())) {
            iReturnCode = schedule.callService(WechatServiceConstant.WECHAT_PUBLIC_CLIENT_SERVICE, HttpMethod.GET);
        } else {
            iReturnCode = schedule.callService(WechatServiceConstant.WECHAT_PUBLIC_CLIENT_SERVICE, HttpMethod.GET);
        }
        if (xmlTreeUtil.isExist(WechatTreeNodeConstant.DEFINE_HTTP_URL_NODE)) {
            xmlTreeUtil.deleteXmlTreeNode(WechatTreeNodeConstant.DEFINE_HTTP_URL_NODE);
        }
        if (0 != iReturnCode) {
            rglog.error("调用微信公众号服务失败，iReturnCode:<{}>", iReturnCode);
            throw new BizException(RespCodeEnum.CALL_BIZ_SERVICE_ERROR.getRespCode(), RespCodeEnum.CALL_BIZ_SERVICE_ERROR.getRespDesc());
        }
        /* 判断调用微信是否成功 */
        String errcode = xmlTreeUtil.getXmlTreeStringValue(WechatTreeNodeConstant.WX_ERR_CODE);
        String errmsg = xmlTreeUtil.getXmlTreeStringValue(WechatTreeNodeConstant.WX_ERR_MSG);
        if (null != errcode) {
            rglog.error("调用微信公众号服务失败,errcode:<{}>,errmsg:<{}>", errcode, errmsg);
            throw new BizException(errcode, errmsg);
        }
        //获取的OPENID返回的accesstoken，非公共基础accessToken,删除该节点，防止影响
        if (xmlTreeUtil.isExist(WechatTreeNodeConstant.ACCESS_TOKEN)) {
            xmlTreeUtil.deleteXmlTreeNode(WechatTreeNodeConstant.ACCESS_TOKEN);
        }
        ConvertUtil.convertOutput(getOpenIdResponse);
        if (!"getPayOrderId".equals(getOpenIdRequest.getHeader().getTxnNum())) {
            sysParam = sysParamService.getSysParamInfo(AppParamConstant.DEFAULT_INSTID,
                    WechatConfigConstant.WECHAT_CONF_NODE, WechatConfigConstant.WECHAT_USER_INFO_URL);
            if (sysParam == null) {
                rglog.info("获取用户信息地址失败，直接返回");
                getOpenIdResponse.setRespCode(RespCodeEnum.TRANS_SUCCESS.getRespCode());
                getOpenIdResponse.setRespDesc(RespCodeEnum.TRANS_SUCCESS.getRespDesc());
                ChnlBizResponse chnlBizResponse = new ChnlBizResponse();
                chnlBizResponse.setResult(getOpenIdResponse);
                return chnlBizResponse;
            }
            /*从redis缓存获取accessToken*/
            String accessToken = RedisUtil.onceGet(WechatParamConstant.ACCESS_TOKEN_CACHE_NAME + dstChannelCfg.getSubAppId());
            if (accessToken == null) {
                accessToken = getAccessToken(dstChannelCfg);
                if (accessToken == null) {
                    getOpenIdResponse.setRespCode(RespCodeEnum.TRANS_SUCCESS.getRespCode());
                    getOpenIdResponse.setRespDesc(RespCodeEnum.TRANS_SUCCESS.getRespDesc());
                    ChnlBizResponse chnlBizResponse = new ChnlBizResponse();
                    chnlBizResponse.setResult(getOpenIdResponse);
                    return chnlBizResponse;
                }
            }

            //String accessToken = getOpenIdResponse.getAccessToken();
            Map<String, String> paramUserMap = new HashMap<>();
            paramUserMap.put("access_token", accessToken);
            paramUserMap.put("openid", getOpenIdResponse.getOpenId());
            paramUserMap.put("lang", "zh_CN");
            requestUrl = generateHttpUrl(sysParam.getParamValue(), paramUserMap);
            xmlTreeUtil.setXmlTreeStringValue(WechatTreeNodeConstant.DEFINE_HTTP_URL_NODE, requestUrl);
            iReturnCode = schedule.callService(WechatServiceConstant.WECHAT_PUBLIC_CLIENT_SERVICE, HttpMethod.GET);
            if (xmlTreeUtil.isExist(WechatTreeNodeConstant.DEFINE_HTTP_URL_NODE)) {
                xmlTreeUtil.deleteXmlTreeNode(WechatTreeNodeConstant.DEFINE_HTTP_URL_NODE);
            }
            if (0 != iReturnCode) {
                rglog.error("调用微信公众号服务获取用户信息失败，iReturnCode:<{}>", iReturnCode);
                getOpenIdResponse.setRespCode(RespCodeEnum.TRANS_SUCCESS.getRespCode());
                getOpenIdResponse.setRespDesc(RespCodeEnum.TRANS_SUCCESS.getRespDesc());
                ChnlBizResponse chnlBizResponse = new ChnlBizResponse();
                chnlBizResponse.setResult(getOpenIdResponse);
                return chnlBizResponse;
            }
            /* 判断调用微信是否成功 */
            errcode = xmlTreeUtil.getXmlTreeStringValue(WechatTreeNodeConstant.WX_ERR_CODE);
            errmsg = xmlTreeUtil.getXmlTreeStringValue(WechatTreeNodeConstant.WX_ERR_MSG);
            if (null != errcode) {
                rglog.error("调用微信公众号服务失败,errcode:<{}>,errmsg:<{}>", errcode, errmsg);
            }
            ConvertUtil.convertOutput(getOpenIdResponse);
        }
        getOpenIdResponse.setRespCode(RespCodeEnum.TRANS_SUCCESS.getRespCode());
        getOpenIdResponse.setRespDesc(RespCodeEnum.TRANS_SUCCESS.getRespDesc());
        ChnlBizResponse chnlBizResponse = new ChnlBizResponse();
        chnlBizResponse.setResult(getOpenIdResponse);
        return chnlBizResponse;
    }

    @Override
    protected void afterBizProcess(ChnlBizResponse response) throws Exception {
        WechatGetOpenIdResponse getOpenIdResponse = (WechatGetOpenIdResponse) response.getResult();
        ConvertUtil.convertInput(getOpenIdResponse);
    }

    /**
     * 根据配置拼装URL地址
     *
     * @param transUrl    URL地址
     * @param urlParamMap URL参数集合
     * @return URL地址
     */
    private String generateHttpUrl(String transUrl, Map<String, String> urlParamMap) {
        String requestUrlParam = "";
        Iterator<String> it = urlParamMap.keySet().iterator();
        while (it.hasNext()) {
            String key = it.next();
            requestUrlParam += key + "=" + urlParamMap.get(key) + "&";
        }
        return transUrl + requestUrlParam.substring(0, requestUrlParam.length() - 1);
    }

    private String getAccessToken(DstChannelCfg dstChannelCfg) throws Exception {
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        String secret = null;
        /* 根据通道安全计划获取安全计划 */
        SecPlanInfoMapper secPlanInfoMapper = new SecPlanInfoMapperImpl();
        List<SecPlanInfo> secPlanInfoList = secPlanInfoMapper.selectSecPlanInfoBySecPlanId(dstChannelCfg.getInstId(), dstChannelCfg.getSecPlanId());
        if (null != secPlanInfoList && !secPlanInfoList.isEmpty()) {
            Optional<SecPlanInfo> secPlanInfoOpt = secPlanInfoList.stream().filter(item -> item.getSecPlanType().equals(WechatParamConstant.SECRET_KEY_TYPE)).findFirst();
            if (secPlanInfoOpt.isPresent()) {
                KeyInfoMapper keyInfoMapper = new KeyInfoMapperImpl();
                KeyInfo keyInfo = keyInfoMapper.selectKeyInfoByPrimaryKey(secPlanInfoOpt.get().getInstId() + secPlanInfoOpt.get().getSecPlanId() + secPlanInfoOpt.get().getSecPlanType());
                if (keyInfo != null) {
                    secret = keyInfo.getKeyValue();
                }
            }
        }
        if (secret == null) {
            rglog.error("获取服务商secret失败");
            return null;
        }
        xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.TXN_NUM, WechatTxnNumConstant.getaccesstoken);
        Map<String, String> paramMap = new HashMap<>();
        paramMap.put("appid", dstChannelCfg.getSubAppId());
        paramMap.put("secret", secret);
        paramMap.put("grant_type", WechatParamConstant.DEFAULT_WECHAT_TOKEN_GRANT_TYPE);
        SysParamService sysParamService = new SysParamServiceImpl();
        SysParam sysParam = sysParamService.getSysParamInfo(dstChannelCfg.getInstId(),
                WechatConfigConstant.WECHAT_CONF_NODE, WechatConfigConstant.WECHAT_ACCESS_TOKEN_URL);
        if (sysParam == null) {
            return null;
        }
        String requestUrl = generateHttpUrl(sysParam.getParamValue(), paramMap);
        xmlTreeUtil.setXmlTreeStringValue(WechatTreeNodeConstant.DEFINE_HTTP_URL_NODE, requestUrl);
        Schedule schedule = new Schedule();
        int iReturnCode = schedule.callService(WechatServiceConstant.WECHAT_PUBLIC_CLIENT_SERVICE, HttpMethod.GET);
        if (0 != iReturnCode) {
            rglog.error("调用微信公众号服务失败，iReturnCode:<{}>", iReturnCode);
            return null;
        }
        /* 判断调用微信是否成功 */
        String errcode = xmlTreeUtil.getXmlTreeStringValue(WechatTreeNodeConstant.WX_ERR_CODE);
        String errmsg = xmlTreeUtil.getXmlTreeStringValue(WechatTreeNodeConstant.WX_ERR_MSG);
        if (null != errcode) {
            rglog.error("调用微信公众号服务失败,errcode:<{}>,errmsg:<{}>", errcode, errmsg);
            return null;
        }
        xmlTreeUtil.deleteXmlTreeNode(WechatTreeNodeConstant.WX_ERR_CODE);
        xmlTreeUtil.deleteXmlTreeNode(WechatTreeNodeConstant.WX_ERR_MSG);
        String accessToken = xmlTreeUtil.getXmlTreeStringValue(WechatTreeNodeConstant.ACCESS_TOKEN);
        /*加载到redis缓存*/
        RedisUtil.onceSet(WechatParamConstant.ACCESS_TOKEN_CACHE_NAME + dstChannelCfg.getSubAppId(), accessToken, WechatParamConstant.ACCESS_TOKEN_EXPIRY_TIME);
        return accessToken;
    }
}
